package com.db.bankapp.domain.bank;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @ThreadSafe Represents bank
 */
public class Bank {
    private final AtomicInteger idSeq = new AtomicInteger(0);
    private final Map<Integer, Client> clients = new LinkedHashMap<>();
    private Set<ClientRegistrationListener> listeners;

    public Bank() {
        listeners = new HashSet<>();
        listeners.add(new PrintClientListener());
        listeners.add(new EmailNotificationListener());
    }

    public Bank(Set<ClientRegistrationListener> listeners) {
        this.listeners = listeners;
    }

    /**
     * Returns copy of clients of the bank
     *
     * @return clients
     */
    public Collection<Client> getClients() {
        return new LinkedHashSet<>(clients.values());
    }

    /**
     * Finds client by id
     *
     * @param id clients id
     * @return client
     */
    public Client getClient(int id) {
        return clients.get(id);
    }

    /**
     * Adds client
     *
     * @param client to add
     * @throws java.lang.NullPointerException when client is null
     */
    public void addClient(Client client) {
        if (client == null) {
            throw new NullPointerException("Client should not be null!");
        }
        clients.put(idSeq.incrementAndGet(), client);
        for (ClientRegistrationListener listener : listeners) {
            listener.onClientAdded(client);
        }
    }

    /**
     * Creates Checking account
     *
     * @param balance   initial balance
     * @param overdraft initial overdraft
     * @return Checking account
     * @throws java.lang.IllegalArgumentException if balance or overdraft is negative
     */
    public static Account createCheckingAccount(int balance, int overdraft) {
        checkBalance(balance);
        if (overdraft < 0) {
            throw new IllegalArgumentException("Overdraft should not be negative!");
        }
        return new CheckingAccount(balance, overdraft);
    }

    /**
     * Creates Saving account
     *
     * @param balance initial balance
     * @return Saving account
     * @throws java.lang.IllegalArgumentException if balance is negative
     */
    public static Account createSavingAccount(int balance) {
        checkBalance(balance);
        return new SavingAccount(balance);
    }

    /**
     * Checking balance
     *
     * @param balance
     * @throws java.lang.IllegalArgumentException if balance is negative
     */
    private static void checkBalance(int balance) {
        if (balance < 0) {
            throw new IllegalArgumentException("Balance should not be negative!");
        }
    }

    /**
     * Add listener to the list of listeners
     *
     * @param listener
     *
     */
    public void registerListener(ClientRegistrationListener listener ) {
        listeners.add(listener);
    }

    /**
     *
     */
    public static class PrintClientListener implements ClientRegistrationListener {
        /**
         * 
         *
         * @param client
         */
        @Override
        public void onClientAdded(Client client) {
            System.out.println(client);
        }
    }

    public static class EmailNotificationListener implements ClientRegistrationListener {

        @Override
        public void onClientAdded(Client client) {
            System.out.println("Notification email for client " + client + " to be sent");
        }
    }


}
